package com.inspur.edp.common.expr;

import com.fasterxml.jackson.databind.JsonNode;
import com.inspur.edp.common.expr.exception.ExpressException;
import com.inspur.edp.common.expr.expresses.array.ArrayAccessExpr;
import com.inspur.edp.common.expr.expresses.calculate.CalculateExpr;
import com.inspur.edp.common.expr.expresses.compare.CompareExpr;
import com.inspur.edp.common.expr.expresses.constant.*;
import com.inspur.edp.common.expr.expresses.field.FieldAccessExpr;
import com.inspur.edp.common.expr.expresses.field.LwFieldAccessExpr;
import com.inspur.edp.common.expr.expresses.help.HelpValueExpr;
import com.inspur.edp.common.expr.expresses.logic.LogicExpr;
import com.inspur.edp.common.expr.expresses.method.MethodInvokeExpr;
import com.inspur.edp.common.expr.expresses.newexp.NewExpr;
import com.inspur.edp.common.expr.expresses.node.NodeVariableExpr;
import com.inspur.edp.common.expr.expresses.not.NotExpress;
import com.inspur.edp.common.expr.expresses.setvalue.AssignValueExpr;
import com.inspur.edp.common.expr.expresses.setvalue.SetValueExpr;
import com.inspur.edp.common.expr.expresses.variable.VariableDefExpr;
import com.inspur.edp.common.expr.expresses.variable.VariableRefExpr;
import com.inspur.edp.common.type.utils.JsonPropUtil;
import com.inspur.edp.common.type.utils.JsonSerializeUtil;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.commons.utils.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * @author lizhaorui
 * @description TODO
 * @date 2025/4/7 17:26
 */
public class ExpressDeserializerMgr {

    private static volatile ExpressDeserializerMgr instance;

    private final Map<String, Class> typeMap = new HashMap<>();

    public static ExpressDeserializerMgr getInstance() {
        if (instance == null) {
            synchronized (ExpressDeserializerMgr.class) {
                if (instance == null) {
                    ExpressDeserializerMgr temp = new ExpressDeserializerMgr();
                    temp.typeMap.put(CalculateExpr.KIND, CalculateExpr.class);
                    temp.typeMap.put(CompareExpr.KIND, CompareExpr.class);
                    temp.typeMap.put(BoolConstExpr.KIND, BoolConstExpr.class);
                    temp.typeMap.put(EnumConstExpr.KIND, EnumConstExpr.class);
                    temp.typeMap.put(NumberConstExpr.KIND, NumberConstExpr.class);
                    temp.typeMap.put(StaticFieldConstExpr.KIND, StaticFieldConstExpr.class);
                    temp.typeMap.put(StringConstExpr.KIND, StringConstExpr.class);
                    temp.typeMap.put(StringsConstExpr.KIND, StringsConstExpr.class);
                    temp.typeMap.put(LogicExpr.KIND, LogicExpr.class);
                    temp.typeMap.put(ArrayAccessExpr.KIND, ArrayAccessExpr.class);
                    temp.typeMap.put(FieldAccessExpr.KIND, FieldAccessExpr.class);
                    temp.typeMap.put(LwFieldAccessExpr.KIND, LwFieldAccessExpr.class);
                    temp.typeMap.put(MethodInvokeExpr.KIND, MethodInvokeExpr.class);
                    temp.typeMap.put(VariableRefExpr.KIND, VariableRefExpr.class);
                    temp.typeMap.put(VariableDefExpr.KIND, VariableDefExpr.class);
                    temp.typeMap.put(SetValueExpr.KIND, SetValueExpr.class);
                    temp.typeMap.put(AssignValueExpr.KIND, AssignValueExpr.class);
                    temp.typeMap.put(NotExpress.KIND, NotExpress.class);
                    temp.typeMap.put(HelpValueExpr.KIND, HelpValueExpr.class);
                    temp.typeMap.put(NewExpr.KIND, NewExpr.class);
                    temp.typeMap.put(NodeVariableExpr.KIND, NodeVariableExpr.class);
                    instance = temp;
                }
            }
        }
        return instance;
    }

    public static Express deserialize(String jsonContent) {
        JsonNode jsonNode = JsonSerializeUtil.toJsonNode(jsonContent);
        return deserialize(jsonNode);
    }

    public static Express deserialize(JsonNode jsonObject) {
        if (jsonObject == null) {
            return null;
        }
        String expressKind = JsonPropUtil.getPropValueAsString(jsonObject, "kind");
        if (StringUtils.isEmpty(expressKind)) {
            return null;
        }
        Class cls = ExpressDeserializerMgr.getInstance().typeMap.get(expressKind);
        if (cls == null) {
            throw new ExpressException(String.format("there is no %s expression deserializer", expressKind));
        }
        if (!jsonObject.isObject()) {
            throw new ExpressException("json node must be object node.");
        }
        return (Express) JsonSerializeUtil.toObject(jsonObject, cls);
    }

}
